home *** CD-ROM | disk | FTP | other *** search
Wrap
/* graphics: gxFont library routines by Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Mike Reed, Oliver Steele, David Van Brink, Chris Yerga Copyright ©1987 - 1991 Apple Computer, Inc. All rights reserved. */ #include <Memory.h> #include <Quickdraw.h> #include "font library.h" #include "graphics libraries.h" #include "font routines.h" #include "graphics toolbox.h" #ifdef THINK_C #pragma options(signed_pstrs) /* for Think C 5.0 */ #endif #ifdef MacintoshIncludes #define NewString gNewString #endif typedef struct { gxFont fontID; char* fullName; } fontNameRecord; static fontNameRecord commonLibraryFonts[] = { { nil, "Chicago" }, { nil, "Courier" }, { nil, "Geneva" }, { nil, "Helvetica" }, { nil, "Monaco" }, { nil, "New York" }, { nil, "Symbol" }, { nil, "Times Roman" } }; /*********************************** * gxShape and gxStyle library routines to handle fonts * ***********************************/ gxFont GetCommonFont(commonFont fontIndex) { if (fontIndex >= firstCommonFont && fontIndex <= lastCommonFont) { if (commonLibraryFonts[fontIndex].fontID == nil) commonLibraryFonts[fontIndex].fontID = FindCNameFont(gxFullFontName, commonLibraryFonts[fontIndex].fullName); return commonLibraryFonts[fontIndex].fontID; } return GXGetDefaultFont(); } void SetShapeCommonFont(gxShape s, commonFont fontIndex) { GXSetShapeFont(s, GetCommonFont(fontIndex)); } void SetStyleCommonFont(gxStyle s, commonFont fontIndex) { GXSetStyleFont(s, GetCommonFont(fontIndex)); } static long CLength(const char *name) { const char *nameEnd = name; while ((*nameEnd++) != 0) ; return nameEnd - name - 1; } gxFont FindCNameFont(gxFontName meaning, const char* name) { gxFont fontID = nil; GXFindFonts(0, meaning, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, CLength(name), (unsigned char *) name, 1, 1, &fontID); return fontID; } gxFont FindPNameFont(gxFontName meaning, const unsigned char name[]) { gxFont fontID = nil; GXFindFonts(0, meaning, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, name[0], &name[1], 1, 1, &fontID); return fontID; } /************ gxFont names *************/ long FindFontCName(gxFont fontID, gxFontName meaning, char name[]) { long length = GXFindFontName(fontID, meaning, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, (unsigned char*)name, nil); if (name) name[length] = 0; return length; } long FindFontPName(gxFont fontID, gxFontName meaning, unsigned char name[]) { long length = GXFindFontName(fontID, meaning, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); if (name) name[0] = length; return length; } long FindStyleFontCName(gxStyle s, gxFontName meaning, char name[]) { gxFont fontID = GXGetStyleFont(s); return(FindFontCName(fontID, meaning, name)); } long FindStyleFontPName(gxStyle s, gxFontName meaning, unsigned char name[]) { gxFont fontID = GXGetStyleFont(s); return(FindFontPName(fontID, meaning, name)); } void SetStylePNamedFont(gxStyle s, const unsigned char name[]) { gxFont fontID = FindPNameFont(gxFullFontName, name); if (fontID != GXGetStyleFont(s)) GXSetStyleFont(s, fontID); } void SetStyleCNamedFont(gxStyle s, const char* name) { gxFont fontID = FindCNameFont(gxFullFontName, name); if (fontID != GXGetStyleFont(s)) GXSetStyleFont(s, fontID); } /************************ * Routines for using GXFindFonts ************************/ long CountFontFamilies(void) { return GXFindFonts(nil, gxFamilyFontName, 0, 0, 0, 0, nil, 1, gxSelectToEnd, nil); } gxFont FindFontFamily(long index, gxFontPlatform platform, gxFontScript script, gxFontLanguage language, long nameLength, const unsigned char *name) { gxFont fontID = nil; GXFindFonts(nil, gxFamilyFontName, platform, script, language, nameLength, name, index, 1, &fontID); return fontID; } long CountFontStyles(gxFont family) { return GXFindFonts(family, 0, 0, 0, 0, 0, nil, 1, gxSelectToEnd, nil); } static gxFont GetFontStyle(gxFont family, long index) { gxFont fontID = nil; GXFindFonts(family, 0, 0, 0, 0, 0, nil, index, 1, &fontID); return fontID; } gxFont FindFontStyle(gxFont family, long index, gxFontPlatform platform, gxFontScript script, gxFontLanguage language, long nameLength, const unsigned char *name) { gxFont fontID = nil; if (index) GXFindFonts(family, 0, 0, 0, 0, 0, nil, index, 1, &fontID); else GXFindFonts(family, gxStyleFontName, platform, script, language, nameLength, name, index, 1, &fontID); return fontID; } /**************************** Style matching routines ****************************/ typedef struct { Fixed minValue; Fixed defaultValue; Fixed maxValue; } descriptorRange; typedef struct { descriptorRange weight; descriptorRange width; descriptorRange slant; } fontMatchDescriptor; typedef struct { Fixed weight; Fixed width; Fixed slant; } fontStyleCoord; /*********************************************/ /* PrepareStyleForMatching */ /* this sets the styles gxFont variations to that of the current gxFont */ /* we'll use this as a master and keep it to do our matching off of */ /* if the gxStyle already has variations then we'll check to see if */ /* the gxFont has axes, if not we'll nuke the variations and set new */ /* ones based upon the 'fdsc' information(GXFindFontDescriptor should*/ /* look at the fond header for old type fonts ??? */ /*********************************************/ static void PrepareStyleForMatching(gxStyle aStyle) { fontStyleCoord coord; gxFont fontID = GXGetStyleFont(aStyle); coord.weight = 1; coord.width = 1; coord.slant = 0; GXFindFontDescriptor(fontID, weightVariationTag, &coord.weight); GXFindFontDescriptor(fontID, widthVariationTag, &coord.width); GXFindFontDescriptor(fontID, slantVariationTag, &coord.slant); /* if (!( GXGetStyleFontVariations(aStyle, nil))) */ { gxFontVariation* variations = (gxFontVariation*)NewPtr(3 * sizeof(gxFontVariation)); { variations[0].name = weightVariationTag; /*will actually check to see if current variations are set*/ variations[0].value = coord.weight; /*then we'll append any needed ones*/ variations[1].name = widthVariationTag; /*need a new routine that will set and create if needed*/ variations[1].value = coord.width; variations[2].name = slantVariationTag; variations[2].value = coord.slant; } GXSetStyleFontVariations(aStyle, 3, variations); DisposePtr((Ptr)variations); } } /* * This builds a complete description of a gxFont as it is being used in a gxStyle. * Use this to compare against the styles in another gxFont family, to find the closest match. */ static void BuildFontStyleCoord(gxStyle aStyle, fontStyleCoord* coord) { gxFont fontID = GXGetStyleFont(aStyle); long i, count; Fixed value; gxFontTableTag aTag; coord->weight = 1; coord->width = 1; coord->slant = 0; GXFindFontDescriptor(fontID, weightVariationTag, &coord->weight); GXFindFontDescriptor(fontID, widthVariationTag, &coord->width); GXFindFontDescriptor(fontID, slantVariationTag, &coord->slant); count = GXGetStyleFontVariations(aStyle, nil); if (count) { gxFontVariation* variations = (gxFontVariation*)NewPtr(count * sizeof(gxFontVariation)); GXGetStyleFontVariations(aStyle, variations); for (i = 0; i < count; i++) { aTag = variations[i].name; value = variations[i].value; if (aTag == weightVariationTag) coord->weight = value; else if (aTag == widthVariationTag) coord->width = value; else if (aTag == slantVariationTag) coord->slant = value; } DisposePtr((Ptr)variations); } } /* * This builds a complete description of a gxFont, giving its ranges for the various styles * weight, width, slant. * If the gxFont does not support a range for a given gxStyle, then min = max = default. */ static void BuildFontMatchDescriptor(gxFont fontID, fontMatchDescriptor* descriptor) { descriptor->weight.minValue = descriptor->weight.defaultValue = descriptor->weight.maxValue = 0; descriptor->width.minValue = descriptor->width.defaultValue = descriptor->width.maxValue = 0; descriptor->slant.minValue = descriptor->slant.defaultValue = descriptor->slant.maxValue = 0; if (GXFindFontDescriptor(fontID, weightVariationTag, &descriptor->weight.defaultValue)) descriptor->weight.minValue = descriptor->weight.maxValue = descriptor->weight.defaultValue; if (GXFindFontDescriptor(fontID, widthVariationTag, &descriptor->width.defaultValue)) descriptor->width.minValue = descriptor->width.maxValue = descriptor->width.defaultValue; if (GXFindFontDescriptor(fontID, slantVariationTag, &descriptor->slant.defaultValue)) descriptor->slant.minValue = descriptor->slant.maxValue = descriptor->slant.defaultValue; GXFindFontVariation(fontID, weightVariationTag, &descriptor->weight.minValue, &descriptor->weight.defaultValue, &descriptor->weight.maxValue, nil); GXFindFontVariation(fontID, widthVariationTag, &descriptor->width.minValue, &descriptor->width.defaultValue, &descriptor->width.maxValue, nil); GXFindFontVariation(fontID, slantVariationTag, &descriptor->slant.minValue, &descriptor->slant.defaultValue, &descriptor->slant.maxValue, nil); } /* * This needs to scale each difference by some amount that balances the various styles * weight, width, slant * This could be a global table, or possible gxFont defined? */ static Fixed ComputeDescriptorMetric(fontStyleCoord* coord, fontMatchDescriptor* descriptor, fontStyleCoord* setting, fontStyleCoord* remaining) { Fixed distance = 0; fontStyleCoord remainBuffer; if (remaining == nil) remaining = &remainBuffer; remaining->weight = remaining->width = remaining->slant = 0; /*setting must fall within the range of descriptor min and max*/ setting->weight = (coord->weight < descriptor->weight.maxValue) ? coord->weight: descriptor->weight.maxValue;/* min of the maximums*/ setting->weight = (setting->weight > descriptor->weight.minValue) ? setting->weight: descriptor->weight.minValue;/* max of the minimums*/ remaining->weight = coord->weight - setting->weight; /* if positive then we need to add more bolding with a textface, if negative we need to take some away*/ distance += (remaining->weight > 0) ? FixedMultiply(remaining->weight , prefwghtweighting): -FixedMultiply(remaining->weight , prefwghtweighting);/*absolute value for distance metric */ setting->width = (coord->width < descriptor->width.maxValue) ? coord->width: descriptor->width.maxValue;/* min of the maximums*/ setting->width = (setting->width > descriptor->width.minValue) ? setting->width: descriptor->width.minValue;/* max of the minimums*/ remaining->width = coord->width - setting->width; /* if positive then we need to extend via textface, if negative we need to condense*/ distance += (remaining->width > 0) ? FixedMultiply(remaining->width , prefwdthweighting): -FixedMultiply(remaining->width , prefwdthweighting);/*absolute value for distance metric */ setting->slant = (coord->slant < descriptor->slant.maxValue) ? coord->slant: descriptor->slant.maxValue;/* min of the maximums*/ setting->slant = (setting->slant > descriptor->slant.minValue) ? setting->slant: descriptor->slant.minValue;/* max of the minimums*/ remaining->slant = coord->slant - setting->slant; /* if positive then we need to skew clockwise via textface, if negative we need to skew counter clockwise*/ /*actually, if there is any slant at all in the coord->slant then we don't want to make an italic gxFont more italic*/ distance += (remaining->slant > 0) ? FixedMultiply(remaining->slant, prefslntweighting): -FixedMultiply(remaining->slant, prefslntweighting);/*absolute value for distance metric this is naturally weighted to be last pref*/ /* could use something like this and then weight it??? distance += FixedDivide(remaining->slant, ff(90) ); */ if(setting->slant) remaining->slant = 0; return distance; } static void AppendVariation(gxFontVariation** variation, gxFontTableTag aTag, Fixed value) { gxFontVariation* var; long size = GetHandleSize((Handle)variation); SetHandleSize((Handle)variation, size + sizeof(gxFontVariation)); var = (gxFontVariation*)((char*)*variation + size); var->name = aTag; var->value = value; } static void CreateCoordVariations(fontStyleCoord* setting, fontMatchDescriptor* descriptor, gxFontVariation* variation) { long count = 0; if (setting->weight != descriptor->weight.defaultValue) { variation[count].name = weightVariationTag; variation[count].value = setting->weight; count++; } if (setting->width != descriptor->width.defaultValue) count++; { variation[count].name = widthVariationTag; variation[count].value = setting->width; count++; } if (setting->slant != descriptor->slant.defaultValue) count++; { variation[count].name = slantVariationTag; variation[count].value = setting->slant; count++; } } /* currently CreateCoordTextFace makes up the difference between the variation axes and the actual settings of the old gxStyle*/ static gxTextFace* CreateCoordTextFace(fontStyleCoord* remainingCoord, fontMatchDescriptor* descriptor, fontStyleCoord* setting) { #pragma unused(setting) gxTextFace* newFace; Fixed newBoldAddition = 0; newFace = (gxTextFace*)NewPtr(sizeof(gxTextFace) + (1 - gxAnyNumber) * sizeof(gxFaceLayer)); newFace->faceLayers = 1; ResetMapping(&newFace->advanceMapping); newFace->faceLayer[0].outlineStyle = nil; newFace->faceLayer[0].outlineFill = gxSolidFill; newFace->faceLayer[0].flags = 0; /*X=default length, Y = desired percentage bold, x = setting weight, y =new percentage bold to apply*/ /* y = XY/x */ /*newBoldAddition = FixedDivide( FixedMultiply(remainingCoord->weight, descriptor->weight.defaultValue), setting->weight);*/ if ( (remainingCoord->weight) && (descriptor->weight.defaultValue == fixed1) ) /*if there is bold left and the gxFont is not natuarally bold*/ /*newBoldAddition = FixedDivide( FixedMultiply(remainingCoord->weight, descriptor->weight.defaultValue), setting->weight);*/ newBoldAddition = fixed1/12; /*this is just a temporary hack until textfaces are nailed down????*/ newBoldAddition *= (remainingCoord->weight > 0) ? 1: -1; /*increase or decrease weight*/ newFace->faceLayer[0].boldOutset.x = newBoldAddition; /*if negative this makes lighter???*/ newFace->faceLayer[0].boldOutset.y = 0; if (remainingCoord->width || remainingCoord->slant) { gxTransform curTransform = newFace->faceLayer[0].outlineTransform = GXNewTransform(); if (remainingCoord->width) { Fixed newWidthFactor = fixed1+ remainingCoord->width; GXScaleTransform(curTransform, newWidthFactor, fixed1, 0, 0); } if (remainingCoord->slant) GXSkewTransform(curTransform, -fixed1/4, 0, 0, 0);/*should do a slope from angle????*/ } else newFace->faceLayer[0].outlineTransform = nil; return newFace; } static gxFont FindMatchingFont(gxStyle currentStyle, gxFont targetFamily, gxFontVariation* newVariations, gxTextFace** newFace) { Fixed bestMetric = ff(32767); gxFont bestFont = targetFamily; fontStyleCoord currentCoord, bestRemaining, bestSetting; fontMatchDescriptor bestDesc; long styleIndex, styleCount; BuildFontStyleCoord(currentStyle, ¤tCoord); /*maybe take this out later??? use preparestyleformatching*/ styleCount = CountFontStyles(targetFamily); for (styleIndex = 1; styleIndex <= styleCount; styleIndex++) { Fixed metric; gxFont targetFont = GetFontStyle(targetFamily, styleIndex); fontStyleCoord remainingCoord, targetSetting; fontMatchDescriptor targetDescriptor; BuildFontMatchDescriptor(targetFont, &targetDescriptor); if(!GXGetFont(targetFont, nil, nil)) DebugStr((const unsigned char *)"\pError in FindMatchingFont with targetFont"); metric = ComputeDescriptorMetric(¤tCoord, &targetDescriptor, &targetSetting, &remainingCoord); if (metric < bestMetric) { bestMetric = metric; bestFont = targetFont; bestDesc = targetDescriptor; bestSetting = targetSetting; bestRemaining = remainingCoord; } } if (newVariations) /*new way we won't have to do this?????*/ CreateCoordVariations(&bestSetting, &bestDesc, newVariations); if (newFace) *newFace = bestMetric ? CreateCoordTextFace(&bestRemaining, &bestDesc, &bestSetting) : nil; return bestFont; } static void DisposeFaceParts(gxTextFace *newFace) { long activeLayer = newFace->faceLayers - 1; do { if (newFace->faceLayer[activeLayer].outlineStyle) GXDisposeStyle(newFace->faceLayer[activeLayer].outlineStyle); if (newFace->faceLayer[activeLayer].outlineTransform) GXDisposeTransform(newFace->faceLayer[activeLayer].outlineTransform); } while (--activeLayer >= 0); DisposePtr((Ptr) newFace); } void SetMatchingStyle(gxFont targetFamily, gxStyle theStyle, long matchInfo) { gxFont toFont; gxTextFace *newFace = nil; gxFontVariation newVariations[3];/*will only match on wght, wdth, slnt*/ gxFont fromFont = GXGetStyleFont(theStyle); boolean toggle = false; if ( !( GXGetStyleFontVariations(theStyle, nil)) ) PrepareStyleForMatching(theStyle); if(matchInfo & useTextFaceMatching) { if(matchInfo & useVariationsMatching) toFont = FindMatchingFont(theStyle, targetFamily, newVariations, &newFace); else toFont = FindMatchingFont(theStyle, targetFamily, nil, &newFace); } if(!(matchInfo & useTextFaceMatching)) { if(matchInfo & useVariationsMatching) toFont = FindMatchingFont(theStyle, targetFamily, newVariations, nil); else toFont = FindMatchingFont(theStyle, targetFamily, nil, nil); } GXSetStyleFont(theStyle, toFont); GXSetStyleFace(theStyle, nil); /*remove any textfaces set will have to do this selectively in the future???*/ if(matchInfo & useVariationsMatching) { short varCount = GXCountFontVariations(toFont); if(varCount) GXSetStyleFontVariations(theStyle, varCount, newVariations); } if(matchInfo & useTextFaceMatching) { if(newFace) GXSetStyleFace(theStyle, newFace); } if (newFace) DisposeFaceParts(newFace); } gxStyle ReturnMatchingStyle(gxFont targetFamily, gxStyle theStyle, long matchInfo) { gxStyle aStyle = GXCopyToStyle(nil, theStyle); SetMatchingStyle(targetFamily, aStyle, matchInfo); return(aStyle); }